#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
原型模式 (Prototype Pattern) - Python实现详解

概述引导：
原型模式通过复制现有实例来创建新对象，避免重复的初始化工作。
对于Java工程师来说，Python的原型模式实现更加灵活和简洁。

学习要点：
1. Python的copy模块使用
2. 深拷贝vs浅拷贝的区别
3. __copy__和__deepcopy__方法的实现
4. 原型注册表的设计

Java对比要点：
- Java需要实现Cloneable接口，Python使用copy模块
- Java的clone()方法需要处理CloneNotSupportedException
- Python的拷贝机制更灵活
- Python支持自定义拷贝行为

关键理解：
原型模式在Python中主要通过copy模块实现，理解深浅拷贝的区别很重要。
"""

import copy
from abc import ABC, abstractmethod
from dataclasses import dataclass, field
from typing import Dict, List, Any, Optional
from datetime import datetime
import json


@dataclass
class Address:
    """地址类 - 用于演示深拷贝"""
    street: str
    city: str
    country: str
    postal_code: str
    
    def __str__(self):
        return f"{self.street}, {self.city}, {self.country} {self.postal_code}"


class Prototype(ABC):
    """
    原型抽象基类
    
    Java对比：
    - Java使用Cloneable接口
    - Python使用ABC更灵活
    - Python不需要处理异常
    """
    
    @abstractmethod
    def clone(self) -> 'Prototype':
        """克隆方法 - 抽象接口"""
        pass
    
    @abstractmethod
    def deep_clone(self) -> 'Prototype':
        """深度克隆方法"""
        pass


class Person(Prototype):
    """
    人员类 - 实现原型模式
    
    Python优势：
    - 使用copy模块简化实现
    - 支持自定义拷贝行为
    - 类型提示增强可读性
    """
    
    def __init__(self, name: str, age: int, address: Address, 
                 skills: List[str] = None, metadata: Dict[str, Any] = None):
        self.name = name
        self.age = age
        self.address = address
        self.skills = skills or []
        self.metadata = metadata or {}
        self.created_at = datetime.now()
        self.clone_count = 0
    
    def clone(self) -> 'Person':
        """
        浅拷贝实现
        
        注意：浅拷贝会共享可变对象的引用
        """
        cloned = copy.copy(self)
        cloned.clone_count = self.clone_count + 1
        return cloned
    
    def deep_clone(self) -> 'Person':
        """
        深拷贝实现
        
        注意：深拷贝会创建所有嵌套对象的副本
        """
        cloned = copy.deepcopy(self)
        cloned.clone_count = self.clone_count + 1
        cloned.created_at = datetime.now()  # 更新创建时间
        return cloned
    
    def __copy__(self):
        """
        自定义浅拷贝行为
        
        Python特色：
        - 可以控制拷贝过程
        - 决定哪些属性需要特殊处理
        """
        # 创建新实例
        cls = self.__class__
        result = cls.__new__(cls)
        
        # 复制属性
        result.name = self.name
        result.age = self.age
        result.address = self.address  # 浅拷贝：共享引用
        result.skills = self.skills.copy()  # 列表的浅拷贝
        result.metadata = self.metadata.copy()  # 字典的浅拷贝
        result.created_at = self.created_at
        result.clone_count = self.clone_count + 1
        
        return result
    
    def __deepcopy__(self, memo):
        """
        自定义深拷贝行为
        
        参数memo用于避免循环引用
        """
        cls = self.__class__
        result = cls.__new__(cls)
        
        # 添加到memo中避免循环引用
        memo[id(self)] = result
        
        # 深拷贝所有属性
        result.name = copy.deepcopy(self.name, memo)
        result.age = copy.deepcopy(self.age, memo)
        result.address = copy.deepcopy(self.address, memo)
        result.skills = copy.deepcopy(self.skills, memo)
        result.metadata = copy.deepcopy(self.metadata, memo)
        result.created_at = datetime.now()  # 新的时间戳
        result.clone_count = self.clone_count + 1
        
        return result
    
    def add_skill(self, skill: str):
        """添加技能"""
        if skill not in self.skills:
            self.skills.append(skill)
    
    def update_address(self, **kwargs):
        """更新地址信息"""
        for key, value in kwargs.items():
            if hasattr(self.address, key):
                setattr(self.address, key, value)
    
    def __str__(self):
        skills_str = ", ".join(self.skills) if self.skills else "无"
        return f"""
姓名: {self.name}
年龄: {self.age}
地址: {self.address}
技能: {skills_str}
创建时间: {self.created_at.strftime('%Y-%m-%d %H:%M:%S')}
克隆次数: {self.clone_count}
        """.strip()


class Document(Prototype):
    """
    文档类 - 另一个原型示例
    
    展示更复杂的原型模式应用
    """
    
    def __init__(self, title: str, content: str, author: Person, 
                 tags: List[str] = None, attachments: List[str] = None):
        self.title = title
        self.content = content
        self.author = author
        self.tags = tags or []
        self.attachments = attachments or []
        self.created_at = datetime.now()
        self.version = 1
    
    def clone(self) -> 'Document':
        """浅拷贝 - 共享作者对象"""
        cloned = copy.copy(self)
        cloned.version = self.version + 1
        cloned.created_at = datetime.now()
        return cloned
    
    def deep_clone(self) -> 'Document':
        """深拷贝 - 复制所有对象"""
        cloned = copy.deepcopy(self)
        cloned.version = self.version + 1
        cloned.created_at = datetime.now()
        return cloned
    
    def __str__(self):
        return f"""
文档标题: {self.title}
作者: {self.author.name}
版本: {self.version}
创建时间: {self.created_at.strftime('%Y-%m-%d %H:%M:%S')}
标签: {', '.join(self.tags) if self.tags else '无'}
附件数量: {len(self.attachments)}
        """.strip()


class PrototypeRegistry:
    """
    原型注册表 - 管理原型实例
    
    Java对比：
    - Java通常使用HashMap存储原型
    - Python的字典更灵活
    - Python支持动态类型
    """
    
    def __init__(self):
        self._prototypes: Dict[str, Prototype] = {}
    
    def register(self, name: str, prototype: Prototype):
        """注册原型"""
        self._prototypes[name] = prototype
    
    def unregister(self, name: str):
        """注销原型"""
        if name in self._prototypes:
            del self._prototypes[name]
    
    def clone(self, name: str) -> Optional[Prototype]:
        """克隆指定原型（浅拷贝）"""
        prototype = self._prototypes.get(name)
        return prototype.clone() if prototype else None
    
    def deep_clone(self, name: str) -> Optional[Prototype]:
        """深度克隆指定原型"""
        prototype = self._prototypes.get(name)
        return prototype.deep_clone() if prototype else None
    
    def list_prototypes(self) -> List[str]:
        """列出所有注册的原型"""
        return list(self._prototypes.keys())
    
    def get_prototype_info(self, name: str) -> str:
        """获取原型信息"""
        prototype = self._prototypes.get(name)
        if prototype:
            return f"{name}: {type(prototype).__name__}"
        return f"{name}: 未找到"


class SerializablePrototype:
    """
    可序列化原型 - Python特色实现
    
    Python优势：
    - 支持JSON序列化
    - 可以跨进程传输
    - 便于持久化存储
    """
    
    def __init__(self, data: Dict[str, Any]):
        self.data = data
        self.created_at = datetime.now()
    
    def to_json(self) -> str:
        """序列化为JSON"""
        serializable_data = {
            'data': self.data,
            'created_at': self.created_at.isoformat()
        }
        return json.dumps(serializable_data, ensure_ascii=False, indent=2)
    
    @classmethod
    def from_json(cls, json_str: str) -> 'SerializablePrototype':
        """从JSON反序列化"""
        data = json.loads(json_str)
        instance = cls(data['data'])
        instance.created_at = datetime.fromisoformat(data['created_at'])
        return instance
    
    def clone(self) -> 'SerializablePrototype':
        """通过序列化实现深拷贝"""
        json_str = self.to_json()
        cloned = self.from_json(json_str)
        cloned.created_at = datetime.now()
        return cloned
    
    def __str__(self):
        return f"SerializablePrototype(data={self.data}, created_at={self.created_at})"


def demonstrate_prototype_pattern():
    """
    演示原型模式的使用
    
    概述引导：
    展示原型模式在Python中的实现和应用，
    包括浅拷贝、深拷贝和注册表模式。
    
    学习要点：
    1. 浅拷贝vs深拷贝的区别
    2. 自定义拷贝行为
    3. 原型注册表的使用
    4. 序列化原型的实现
    
    关键理解：
    原型模式通过复制现有对象来创建新对象，避免重复初始化。
    """
    print("=== 原型模式演示 ===")
    print("\n学习目标：")
    print("- 理解浅拷贝和深拷贝的区别")
    print("- 掌握自定义拷贝行为")
    print("- 学习原型注册表模式")
    print("\n重点概念：")
    print("- 对象克隆机制")
    print("- 引用共享vs对象复制")
    print("- 原型管理策略")
    print("=" * 50)
    
    # 创建原始对象
    address = Address("中关村大街1号", "北京", "中国", "100080")
    person = Person("张三", 30, address, ["Python", "Java"], {"level": "senior"})
    
    print("\n1. 原始对象：")
    print(person)
    print(f"对象ID: {id(person)}")
    print(f"地址对象ID: {id(person.address)}")
    
    # 浅拷贝演示
    print("\n2. 浅拷贝演示：")
    shallow_clone = person.clone()
    print("浅拷贝对象：")
    print(shallow_clone)
    print(f"对象ID: {id(shallow_clone)}")
    print(f"地址对象ID: {id(shallow_clone.address)}")
    
    # 修改原始对象的地址
    print("\n修改原始对象的地址...")
    person.update_address(street="中关村大街2号")
    print(f"原始对象地址: {person.address}")
    print(f"浅拷贝对象地址: {shallow_clone.address}")
    print("注意：浅拷贝共享地址对象的引用！")
    
    # 深拷贝演示
    print("\n3. 深拷贝演示：")
    deep_clone = person.deep_clone()
    print("深拷贝对象：")
    print(deep_clone)
    print(f"对象ID: {id(deep_clone)}")
    print(f"地址对象ID: {id(deep_clone.address)}")
    
    # 修改原始对象
    print("\n修改原始对象的地址和技能...")
    person.update_address(street="中关村大街3号")
    person.add_skill("Go")
    print(f"原始对象地址: {person.address}")
    print(f"深拷贝对象地址: {deep_clone.address}")
    print(f"原始对象技能: {person.skills}")
    print(f"深拷贝对象技能: {deep_clone.skills}")
    print("注意：深拷贝创建了独立的对象副本！")


def demonstrate_prototype_registry():
    """
    演示原型注册表的使用
    """
    print("\n=== 原型注册表演示 ===")
    
    # 创建注册表
    registry = PrototypeRegistry()
    
    # 创建原型对象
    address1 = Address("软件园路1号", "深圳", "中国", "518000")
    developer = Person("李四", 28, address1, ["Python", "Django"], {"level": "mid"})
    
    address2 = Address("科技路2号", "上海", "中国", "200000")
    manager = Person("王五", 35, address2, ["管理", "架构"], {"level": "senior"})
    
    # 注册原型
    registry.register("developer_template", developer)
    registry.register("manager_template", manager)
    
    print("已注册的原型：")
    for name in registry.list_prototypes():
        print(f"- {registry.get_prototype_info(name)}")
    
    # 克隆原型
    print("\n克隆开发者模板：")
    new_developer = registry.clone("developer_template")
    if new_developer:
        new_developer.name = "赵六"
        new_developer.age = 26
        print(new_developer)
    
    print("\n深度克隆管理者模板：")
    new_manager = registry.deep_clone("manager_template")
    if new_manager:
        new_manager.name = "孙七"
        new_manager.age = 40
        new_manager.update_address(city="广州")
        print(new_manager)
        print(f"\n原始管理者地址: {manager.address}")
        print(f"新管理者地址: {new_manager.address}")


def demonstrate_document_cloning():
    """
    演示文档克隆
    """
    print("\n=== 文档克隆演示 ===")
    
    # 创建作者
    author_address = Address("学院路1号", "北京", "中国", "100000")
    author = Person("张教授", 45, author_address, ["研究", "写作"])
    
    # 创建文档
    doc = Document(
        "Python设计模式研究",
        "本文档详细介绍了Python中的设计模式实现...",
        author,
        ["设计模式", "Python", "编程"],
        ["diagram1.png", "code_example.py"]
    )
    
    print("原始文档：")
    print(doc)
    
    # 浅拷贝文档
    print("\n浅拷贝文档：")
    doc_copy = doc.clone()
    doc_copy.title = "Java设计模式研究"
    print(doc_copy)
    
    # 修改原始作者信息
    print("\n修改原始作者年龄...")
    author.age = 46
    print(f"原始文档作者年龄: {doc.author.age}")
    print(f"拷贝文档作者年龄: {doc_copy.author.age}")
    print("注意：浅拷贝共享作者对象！")
    
    # 深拷贝文档
    print("\n深拷贝文档：")
    doc_deep_copy = doc.deep_clone()
    doc_deep_copy.title = "Go设计模式研究"
    doc_deep_copy.author.name = "李教授"
    print(doc_deep_copy)
    print(f"\n原始文档作者: {doc.author.name}")
    print(f"深拷贝文档作者: {doc_deep_copy.author.name}")


def demonstrate_serializable_prototype():
    """
    演示可序列化原型
    """
    print("\n=== 可序列化原型演示 ===")
    
    # 创建可序列化原型
    data = {
        "name": "配置模板",
        "settings": {
            "database": "mysql",
            "cache": "redis",
            "debug": True
        },
        "features": ["logging", "monitoring", "backup"]
    }
    
    prototype = SerializablePrototype(data)
    print("原始原型：")
    print(prototype)
    
    # 序列化
    json_str = prototype.to_json()
    print("\n序列化结果：")
    print(json_str)
    
    # 反序列化
    restored = SerializablePrototype.from_json(json_str)
    print("\n反序列化对象：")
    print(restored)
    
    # 克隆
    cloned = prototype.clone()
    cloned.data["name"] = "生产配置"
    cloned.data["settings"]["debug"] = False
    
    print("\n克隆并修改后：")
    print(f"原始: {prototype.data['name']}, debug={prototype.data['settings']['debug']}")
    print(f"克隆: {cloned.data['name']}, debug={cloned.data['settings']['debug']}")


def demonstrate_java_comparison():
    """
    Java对比演示
    
    Java等价代码：
    ```java
    // Java版本需要实现Cloneable接口
    public class Person implements Cloneable {
        private String name;
        private int age;
        private Address address;
        private List<String> skills;
        
        @Override
        public Person clone() throws CloneNotSupportedException {
            Person cloned = (Person) super.clone();
            // 需要手动处理深拷贝
            cloned.address = this.address.clone();
            cloned.skills = new ArrayList<>(this.skills);
            return cloned;
        }
    }
    
    // 使用时需要处理异常
    try {
        Person cloned = original.clone();
    } catch (CloneNotSupportedException e) {
        // 处理异常
    }
    ```
    
    Python优势：
    1. copy模块提供标准化拷贝机制
    2. 不需要处理异常
    3. 支持自定义拷贝行为
    4. 深浅拷贝机制更清晰
    """
    print("\n=== Java对比说明 ===")
    print("\nPython优势：")
    print("1. copy模块提供标准拷贝机制")
    print("2. 不需要处理CloneNotSupportedException")
    print("3. __copy__和__deepcopy__方法更灵活")
    print("4. 深浅拷贝概念更清晰")
    print("5. 支持序列化克隆")
    
    print("\nJava特点：")
    print("1. Cloneable接口标记")
    print("2. 需要显式处理异常")
    print("3. 类型安全更严格")
    print("4. 需要手动实现深拷贝逻辑")


def performance_comparison():
    """
    性能对比测试
    """
    import time
    
    print("\n=== 性能对比 ===")
    
    # 创建测试对象
    address = Address("测试街道", "测试城市", "测试国家", "000000")
    person = Person("测试", 25, address, ["skill1", "skill2"], {"key": "value"})
    
    # 测试浅拷贝
    start_time = time.time()
    for i in range(10000):
        cloned = person.clone()
    shallow_time = time.time() - start_time
    
    # 测试深拷贝
    start_time = time.time()
    for i in range(10000):
        cloned = person.deep_clone()
    deep_time = time.time() - start_time
    
    # 测试序列化克隆
    serializable = SerializablePrototype({"test": "data", "list": [1, 2, 3]})
    start_time = time.time()
    for i in range(1000):  # 较少次数，因为序列化较慢
        cloned = serializable.clone()
    serialize_time = time.time() - start_time
    
    print(f"浅拷贝 (10000次): {shallow_time:.4f}秒")
    print(f"深拷贝 (10000次): {deep_time:.4f}秒")
    print(f"序列化克隆 (1000次): {serialize_time:.4f}秒")
    print(f"深拷贝比浅拷贝慢: {deep_time/shallow_time:.2f}倍")


if __name__ == "__main__":
    demonstrate_prototype_pattern()
    demonstrate_prototype_registry()
    demonstrate_document_cloning()
    demonstrate_serializable_prototype()
    demonstrate_java_comparison()
    performance_comparison()